package com.zte.claa.inficombo.csa.app.service.sapi.ffhost.mina;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;

import org.apache.mina.core.buffer.IoBuffer;

import com.zte.claa.inficombo.csa.app.util.EdianUtil;
import com.zte.claa.inficombo.csa.app.util.SecurityUtil;

public class FFTransDevMessage {
	public static final short CMD_CONTROL  = 1;
	public static final short CMD_RPTDATA  = 2;
	public static final short CMD_CONFIRM  = 3;
	public static final short CMD_REQUEST  = 4;
	public static final short CMD_RESPONSE = 5;
	public static final short CMD_DENYACK  = 6;
	
	public static final byte START_CHAR = 64;
	public static final byte END_CHAR = 35;
	
	private byte startB1 = START_CHAR;
	private byte startB2 = START_CHAR;
	
	// 两个字节的正整数.
	private int sno = -1;
	// 版本号:主.子版本号.
	private byte mainVersion = 1;
	private byte userVersion = 0;
	// 时间字段：6个字节，依次为：秒.分.时.日.月.年.
	private byte second = 0;
	private byte minute = 0;
	private byte hour = 0;
	private byte day = 1;
	private byte month = 1;
	private byte year = 19;
	// 源地址（6个字节，低字节在前）
	private String srcAddr = "0";
	// 目标地址（6个字节，低字节在前）
	private String dstAdrr = "0";
	// 命令字
	private byte cmd = 0;
	// 应用数据载荷
	private byte[] data = new byte[0];
	// 校验和
	private byte checkSum = 0;
	// 结束符
	private byte endB1 = END_CHAR;
	private byte endB2 = END_CHAR;
	
	// 最小字节数.
	public static int getMinMsgSize() {
		return 30;
	}
	
	public FFTransDevMessage(){
		
	}

	public byte getStartB1() {
		return startB1;
	}

	public void setStartB1(byte startB1) {
		this.startB1 = startB1;
	}

	public byte getStartB2() {
		return startB2;
	}

	public void setStartB2(byte startB2) {
		this.startB2 = startB2;
	}

	public int getSno() {
		return sno;
	}

	public void setSno(int sno) {
		this.sno = sno;
	}

	public byte getMainVersion() {
		return mainVersion;
	}

	public void setMainVersion(byte mainVersion) {
		this.mainVersion = mainVersion;
	}

	public byte getUserVersion() {
		return userVersion;
	}

	public void setUserVersion(byte userVersion) {
		this.userVersion = userVersion;
	}

	public byte getSecond() {
		return second;
	}

	public void setSecond(byte second) {
		this.second = second;
	}

	public byte getMinute() {
		return minute;
	}

	public void setMinute(byte minute) {
		this.minute = minute;
	}

	public byte getHour() {
		return hour;
	}

	public void setHour(byte hour) {
		this.hour = hour;
	}

	public byte getDay() {
		return day;
	}

	public void setDay(byte day) {
		this.day = day;
	}

	public byte getMonth() {
		return month;
	}

	public void setMonth(byte month) {
		this.month = month;
	}

	public byte getYear() {
		return year;
	}

	public void setYear(byte year) {
		this.year = year;
	}

	public String getSrcAddr() {
		return srcAddr;
	}

	public void setSrcAddr(String srcAddr) {
		this.srcAddr = srcAddr;
	}

	public String getDstAdrr() {
		return dstAdrr;
	}

	public void setDstAdrr(String dstAdrr) {
		this.dstAdrr = dstAdrr;
	}

	public int getDataLength() {
		return (this.data == null) ? 0 : this.data.length;
	}

	public byte getCmd() {
		return cmd;
	}

	public void setCmd(byte cmd) {
		this.cmd = cmd;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	public byte getCheckSum() {
		return checkSum;
	}

	public void setCheckSum(byte checkSum) {
		this.checkSum = checkSum;
	}

	public byte getEndB1() {
		return endB1;
	}

	public void setEndB1(byte endB1) {
		this.endB1 = endB1;
	}

	public byte getEndB2() {
		return endB2;
	}

	public void setEndB2(byte endB2) {
		this.endB2 = endB2;
	}
	
	// 获取msg时间的毫秒数.
	public long getMsgTimeOfMillSeconds(){
		// "2007-12-03T10:15:30"
		LocalDateTime dt = LocalDateTime.of(2000+this.year, this.month, this.day, this.hour, this.minute, this.second);
		return dt.toInstant(ZoneOffset.of("+8")).toEpochMilli();
	}
	
	// 设置时间戳.
	public void setMsgTime(long millSeconds){
		Date date = new Date(millSeconds);
		LocalDateTime localDateTime = date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
		this.year = (byte)(localDateTime.getYear() - 2000);
		this.month = (byte)(localDateTime.getMonthValue());
		this.day = (byte)(localDateTime.getDayOfMonth());
		this.hour = (byte)(localDateTime.getHour());
		this.minute = (byte)(localDateTime.getMinute());
		this.second = (byte)(localDateTime.getSecond());
	}
	
	// 起始字符有效性检查.
	public boolean startFlagCheck() {
		if(this.startB1 == START_CHAR && this.startB2 == START_CHAR){
			return true;
		}
		return false;
	}
	
	// 结束字符有效性检查.
	public boolean endFlagCheck(){
		if(this.endB1 == END_CHAR && this.endB2 == END_CHAR){
			return true;
		}
		return false;
	}
	
	// 校验和检查
	public boolean sumCheckFlagCheck() {
		return this.checkSum == this.calculateSumCheck();
	}
	
	// 校验和检查
	public byte calculateSumCheck() {
		IoBuffer buf = IoBuffer.allocate(FFTransDevMessage.getMinMsgSize(), false).setAutoExpand(true);
		// 2.流水号.
		byte[] bs = new byte[]{0, 0, 0, 0};
		EdianUtil.intToByte_LH(this.sno, bs, 0);
		buf.put(bs[0]);
		buf.put(bs[1]);
		// 3.编码版本号
		buf.put(this.mainVersion);
		buf.put(this.userVersion);
		// 4.时间戳.
		buf.put(this.second);
		buf.put(this.minute);
		buf.put(this.hour);
		buf.put(this.day);
		buf.put(this.month);
		buf.put(this.year);
		// 5.源地址
		buf.put(this.getSrcAddrBytes());
		// 6.目标地址
		buf.put(this.getDstAddrBytes());
		// 7.应用数据字节长度
		int dateLength = this.getDataLength();
		bs = new byte[]{0, 0, 0, 0};
		EdianUtil.intToByte_LH(dateLength, bs, 0);
		buf.put(bs[0]);
		buf.put(bs[1]);
		// 8.命令字
		buf.put(this.cmd);
		// 9. 应用数据
		if(this.data != null && this.data.length > 0){
			buf.put(this.data);
		}
		// 10.校验和
		buf.flip();
		byte[] bsArr = buf.array();
		int len = (bsArr.length < buf.limit()) ? bsArr.length : buf.limit();
		byte[] tmpBs = new byte[len];
		for(int i=0; i<len; i++){
			tmpBs[i] = bsArr[i];
		}
		byte sumChkRet = SecurityUtil.SumCheck(tmpBs, 0);
		buf.clear();
		buf.free();
		buf = null;
		return sumChkRet;
	}
	
	/**
	 * 获取地址字节
	 * 
	 * @return
	 */
	public byte[] getSrcAddrBytes(){
		if(this.srcAddr == null || this.srcAddr.trim().equals("")){
			return new byte[]{0,0,0,0,0,0};
		}
		long lv = Long.parseLong(this.srcAddr);
		byte[] ret = new byte[6];
		for(int i=0; i<6; i++){
			ret[i] = (byte)(lv >> (i*8) & 0xff);
		}
		return ret;
	}
	
	/**
	 * 获取地址字节 (bs的长度固定是6，符合消防GB的地址规范）
	 * 
	 * @return
	 */
	public void setSrcAddrBytes(byte[] bs){
		if(bs == null || bs.length == 0){
			this.srcAddr = "0";
			return;
		}
		long lv = 0;
		for(int i=0; i<bs.length; i++){
			lv = lv | (((bs[i] & 0x00ffL) << (i*8)) & (0x00000000000000ffL << (i*8)));
		}
		this.srcAddr = String.valueOf(lv);  
	}
	
	/**
	 * 获取地址字节
	 * 
	 * @return
	 */
	public byte[] getDstAddrBytes(){
		if(this.dstAdrr == null || this.dstAdrr.trim().equals("")){
			return new byte[]{0,0,0,0,0,0};
		}
		long lv = Long.parseLong(this.dstAdrr);
		byte[] ret = new byte[6];
		for(int i=0; i<6; i++){
			ret[i] = (byte)(lv >> (i*8) & 0xff);
		}
		return ret;
	}
	
	/**
	 * 获取地址字节 (bs的长度固定是6，符合消防GB的地址规范）
	 * 
	 * @return
	 */
	public void setDstAddrBytes(byte[] bs){
		if(bs == null || bs.length == 0){
			this.dstAdrr = "0";
			return;
		}
		long lv = 0;
		for(int i=0; i<bs.length; i++){
			lv = lv | (((bs[i] & 0x00ffL) << (i*8)) & (0x00000000000000ffL << (i*8)));
		}
		this.dstAdrr = String.valueOf(lv);  
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("start=").append(startB1).append(startB2).append(",");
		sb.append("sno=").append(sno).append(",");
		sb.append("version[m.s]=").append(mainVersion).append(".").append(userVersion);
		sb.append("datetime[s.m.h.d.M.y]=").append(second).append(".").append(minute).append(".").append(hour);
		sb.append("-").append(day).append(".").append(month).append(".").append(year).append(",");
		sb.append("srcaddr=").append(this.srcAddr).append(",");
		sb.append("dstaddr=").append(this.dstAdrr).append(",");
		sb.append("cmd=").append(cmd).append(",");
		sb.append("appdata=");
		if(data != null){
			for(byte b : data){
				sb.append(b).append(".");
			}
		}		
		sb.append(",");
		sb.append("checkSum=").append(checkSum).append(",");
		sb.append("end=").append(endB1).append(endB2);
		return sb.toString();
	}
}
